﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using IGM.DataProvider.Entites;

namespace IGM.DataProvider
{
    public class IgmModelContext : ObjectContext
    {
        public IgmModelContext()
            : base("name=IgmModelContainer", "IgmModelContainer")
        {
            ContextOptions.LazyLoadingEnabled = true;
        }

        public IEnumerable<T> GetObjectSet<T>(params string[] includeSets) where T : DataManagement
        {
            var objectSet = CreateObjectSet<T>();
            ObjectQuery<T> result = objectSet;
            return includeSets.Length > 0 ? includeSets.Aggregate(result, (current, includeSet) => current.Include(includeSet)) : objectSet;
        }

        public IEnumerable<int> GetIdFromQuery(string query)
        {
            var objectSet = ExecuteStoreQuery<int>(query);
            return objectSet;
        }

        public IEnumerable<T> GetObjectSet<T>(string[] orderBy, params string[] includeSets) where T : DataManagement
        {
            var objectSet = orderBy == null ? CreateObjectSet<T>() : CreateObjectSet<T>().OrderBy("it." + orderBy[0]);

            if (includeSets != null && includeSets.Length > 0)
            {
                objectSet = includeSets.Aggregate(objectSet, (current, includeSet) => current.Include(includeSet));
            }
            return objectSet;
        }

        public IEnumerable<T> GetObjectSet<T>(string[] orderBy, int take, int skip, params string[] includeSets) where T : DataManagement
        {
            var objectSet = orderBy == null ? CreateObjectSet<T>() : CreateObjectSet<T>().OrderBy("it." + orderBy[0]);

            var result = objectSet;
            if (includeSets != null && includeSets.Length > 0)
            {
                result = includeSets.Aggregate(result, (current, includeSet) => current.Include(includeSet));
                return result.Skip(skip).Take(take);
            }
            return objectSet.Skip(skip).Take(take);
        }

        public IEnumerable<T> GetObjectSet<T>(Expression<Func<T, bool>> query, params string[] includeSets) where T : DataManagement
        {
            var objectSet = CreateObjectSet<T>();
            ObjectQuery<T> result = objectSet;
            if (includeSets != null && includeSets.Length > 0)
            {
                result = includeSets.Aggregate(result, (current, includeSet) => current.Include(includeSet));
                return result.Where(query);
            }
            return objectSet.Where(query);
        }

        public IEnumerable<T> GetObjectSet<T>(Expression<Func<T, bool>> query, int take, int skip, params string[] includeSets) where T : DataManagement
        {
            var objectSet = CreateObjectSet<T>();
            ObjectQuery<T> result = objectSet;
            if (includeSets != null && includeSets.Length > 0)
            {
                result = includeSets.Aggregate(result, (current, includeSet) => current.Include(includeSet));
                return result.Where(query).Skip(skip).Take(take);
            }
            return objectSet.Where(query).Skip(skip).Take(take);
        }

        public T GetObject<T>(Expression<Func<T, bool>> query, params string[] includeSets) where T : DataManagement
        {
            var objectSet = CreateObjectSet<T>();
            ObjectQuery<T> result = objectSet;
            if (includeSets.Length > 0)
            {
                result = includeSets.Aggregate(result, (current, includeSet) => current.Include(includeSet));
                return result.Where(query).FirstOrDefault();
            }
            return objectSet.Where(query).FirstOrDefault();
        }

        public void InsertObject<T>(string setName, T entity) where T : DataManagement
        {
            AddObject(setName, entity);
            SaveChanges();
        }

        public void InsertObject<T>(string setName, T entity, bool isSave) where T : DataManagement
        {
            AddObject(setName, entity);
            if (isSave)
                SaveChanges();
        }

        public void AttachObject<T>(string setName, T entity) where T : DataManagement
        {
            AttachTo(setName, entity);
        }

        public void DetachObject<T>(T entity) where T : DataManagement
        {
            Detach(entity);
        }

        public void UpdateObject()
        {
            SaveChanges();
        }

        public void DeleteObject<T>(T entity) where T : DataManagement
        {
            base.DeleteObject(entity);
            SaveChanges();
        }

        public void DeleteObject<T>(T entity, bool isSave) where T : DataManagement
        {
            base.DeleteObject(entity);
            if (isSave)
                SaveChanges();
        }       
    }
}
